﻿using System;
using System.Collections.Concurrent;
using System.Linq;
using WatchDog.WatchItemManages;
using Serilog;
using System.Threading.Tasks;

namespace WatchDog.WinService
{
    /// <summary>
    /// 延时作业管理，必须按顺序调用 1. BeforeAddOrUpdate()  2. AddOrUpdate() 3. AfterAddOrUpdate();
    /// </summary>
    public static class DelayedJobManager
    {
        private static ConcurrentDictionary<string, DelayedJob> _jobs = new ConcurrentDictionary<string, DelayedJob>();

        private static long _lastActionTimestamp;
        private static bool _ing = false;
 
        public static void AddOrUpdate(WatchItem watchItem,  Func<Task> func)
        {
            if (!_ing)
                return;

            _jobs.AddOrUpdate(watchItem.FilePath, new DelayedJob()
            {
                Id = watchItem.FilePath,
                JobTask = new DelayedTask(watchItem.DelayStart * 1000, func),
                WatchConcurrencyStamp = watchItem.ConcurrencyStamp,
                LastActionTimestamp = _lastActionTimestamp
            }, (_, job) =>
            {
                job.LastActionTimestamp = _lastActionTimestamp;

                if (job.WatchConcurrencyStamp != watchItem.ConcurrencyStamp && job.JobTask.MillisecondsDelay != watchItem.DelayStart * 1000) // 检测配置是否有更新
                {
                    job.JobTask.Cancel(); //取消先前的作业
                    job.JobTask = new DelayedTask(watchItem.DelayStart * 1000, func);
                    job.WatchConcurrencyStamp = watchItem.ConcurrencyStamp;
                }
                return job;
            }) ;
        }

        /// <summary>
        /// 添加或更新前准备工作，复位和效对时间
        /// </summary>
        public static void BeforeAddOrUpdate(long ticks)
        {
            _lastActionTimestamp = ticks;
            _ing = true;
            // 清理已完成的任务
            var jobs = _jobs.Where(c => c.Value.JobTask.IsCompleted);
            foreach (var job in jobs)
            {
                _jobs.TryRemove(job);
            }
        }

        /// <summary>
        /// 添加或更新后清理工作，清理过时的任务，作业可能删除或修改监控项而失效。
        /// </summary>
        public static void AfterAddOrUpdate()
        {
            if (!_ing)
                return;

            var jobs = _jobs.Where(c => c.Value.LastActionTimestamp != _lastActionTimestamp);// 
            foreach (var job in jobs)
            {
                job.Value.JobTask.Cancel();
                _jobs.TryRemove(job);
            }
            _ing = false;
        }

        /// <summary>
        /// 清除全部任务
        /// </summary>
        public static void Clear()
        {
            foreach (var job in _jobs)
            {
                job.Value.JobTask.Cancel();
                _jobs.TryRemove(job);
            }
            _ing = false;
        }
    }

}
